package com.tlgen.modules.security.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.tlgen.common.annotation.EnableTlgenAnonymousAccess;
import com.tlgen.common.exception.BadRequestException;
import com.tlgen.common.utils.RedisUtils;
import com.tlgen.common.utils.SecurityUtils;
import com.tlgen.modules.security.config.SecurityProperties;
import com.tlgen.modules.security.security.TokenProvider;
import com.tlgen.modules.security.security.vo.AuthUser;
import com.tlgen.modules.security.security.vo.JwtUser;
import com.tlgen.modules.security.service.OnlineUserService;
import com.wf.captcha.ArithmeticCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/*import com.tlgen.logging.aop.log.EnableTlgenLog;*/

/**功能描述：授权、根据token获取用户详细信息
 */
@Service
@RestController
@RequestMapping("/auth")
@Api(tags = "系统：系统授权接口")
public class AuthController {

    //验证码过期时间
    @Value("${loginCode.expiration}")
    private Long expiration;
    //后端私钥解密
    @Value("${rsa.private_key}")
    private String privateKey;

    //账号是否多次登录
    @Value("${single.login:false}")
    private Boolean singleLogin;

    private final SecurityProperties properties;
    private final RedisUtils redisUtils;
    private final UserDetailsService userDetailsService;
    private final OnlineUserService onlineUserService;
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    /**
     * 构造方法
     * @param properties
     * @param redisUtils
     * @param userDetailsService
     * @param onlineUserService
     * @param tokenProvider
     * @param authenticationManagerBuilder
     */
    public AuthController(SecurityProperties properties, RedisUtils redisUtils, UserDetailsService userDetailsService, OnlineUserService onlineUserService, TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.properties = properties;
        this.redisUtils = redisUtils;
        this.userDetailsService = userDetailsService;
        this.onlineUserService = onlineUserService;
        this.tokenProvider = tokenProvider;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }




  @EnableTlgenAnonymousAccess
  @ApiOperation("获取验证码")
  @GetMapping("/code")
  public ResponseEntity<Object> getCode(){
        //算术类型
      ArithmeticCaptcha captcha = new ArithmeticCaptcha(111,36);
      //几位数运算，默认是两位
      captcha.setLen(2);
      //获取运行的结果
      String result = captcha.text();
      String uuid = properties.getCodeKey()+ IdUtil.simpleUUID();
      //保存
      redisUtils.set(uuid,result,expiration, TimeUnit.MINUTES);
      //返回验证码信息
      Map<String,Object> imgResult = new HashMap<String,Object>(2){{
          put("img",captcha.toBase64());
          put("uuid",uuid);
      }};

      return ResponseEntity.ok(imgResult);
  }


/*  @EnableTlgenLog("用户登录")*/
  @ApiOperation("登录授权")
  @EnableTlgenAnonymousAccess
  @PostMapping(value = "/login")
  public ResponseEntity<Object> login(@Validated @RequestBody AuthUser authUser,
                                      HttpServletRequest request){

        //密码解密
      RSA rsa = new RSA(privateKey,null);
      String password = new String(rsa.decrypt(authUser.getPassword(), KeyType.PrivateKey));

      //查询验证码
      String code = (String) redisUtils.get(authUser.getUuid());

      //清除验证码
      redisUtils.del(authUser.getUuid());

      //判断验证是否为空
      if(StringUtils.isBlank(code)){
          throw  new BadRequestException("验证码不存在或已过期");
      }

      //判断用户输入的验证码是否正确
      if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) {
          throw new BadRequestException("验证码错误");
      }

      //根据用户和密码获取token
      UsernamePasswordAuthenticationToken authenticationToken =
              new UsernamePasswordAuthenticationToken(authUser.getUsername(),password);

      //成功认证后AuthenticationManager将返回一个得到完整填充的Authentication实例
      Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
      //建立安全上下文
      SecurityContextHolder.getContext().setAuthentication(authentication);

      //生成令牌
      String token = tokenProvider.createToken(authentication);
      final JwtUser jwtUser = (JwtUser)authentication.getPrincipal();

      //保存在线用户信息
      onlineUserService.save(jwtUser,token,request);
      //返回token与用户信息
      Map<String,Object> authInfo = new HashMap<String,Object>(2){{
          put("token", properties.getTokenStartWith() + token);
          put("user", jwtUser);
      }};

      if(singleLogin){
          //踢掉之前已经登录的token
          onlineUserService.checkLoginOnUser(authUser.getUsername(),token);
      }

      return ResponseEntity.ok(authInfo);
  }


  @ApiOperation("获取用户信息")
  @GetMapping("/info")
  public ResponseEntity<Object> getUserInfo(){
    JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(SecurityUtils.getUsername());
    return ResponseEntity.ok(jwtUser);
  }

    @ApiOperation("退出登录")
    @EnableTlgenAnonymousAccess
    @DeleteMapping(value = "/logout")
    public ResponseEntity<Object> logout(HttpServletRequest request){
        onlineUserService.logout(tokenProvider.getToken(request));
        return new ResponseEntity<>(HttpStatus.OK);
    }

}
